﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Diagnostics.CodeAnalysis;

using Fuse8.DomainFramework.Domain;
using Fuse8.DomainFramework.CacheService;

namespace Fuse8.DomainFramework.DataAccess
{
    /// <summary>
    /// Entity object repository
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    public interface IEntityDataRepository<TEntity, TKey> 
        where TEntity : class, IEntityObject<TKey>
        where TKey : IComparable<TKey>, IEquatable<TKey> 
    {
        /// <summary>
        /// Adds a new entity in to the repository
        /// </summary>
        void Add(TEntity entityObject);

        /// <summary>
        /// Saves existing entity to the repository
        /// </summary>
        void Save(TEntity entityObject);

        /// <summary>
        /// Removes the specified entity from the repository
        /// </summary>
        void Remove(TEntity entityObject);

        /// <summary>
        /// Remove from repository by unique identifier
        /// </summary>
        /// <param name="id"></param>
        void Remove(TKey id);

        /// <summary>
        /// Finds a single instance of an entity matching a unique identifier
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        TEntity FindOne(TKey id);

        /// <summary>
        /// Finds a single instance of an entity matching a lambda expression
        /// </summary>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
            Justification = "Uses non-compiled linq expression")]
        TEntity FindOne(Expression<Func<TEntity, bool>> expression);

    	/// <summary>
    	/// Finds a single instance of an entity matching a lambda expression
    	/// </summary>
    	/// <param name="expression">Find expression</param>
    	/// <param name="selectExpression">Expressions present the properties to be selected</param>
    	[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
            Justification = "Uses non-compiled linq expression")]
		TEntity FindOne(Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity, object>> selectExpression);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        TEntity FindOne(IEntityCommand<TEntity> command);

        /// <summary>
        /// Finds all entities matching a lambda expression
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
            Justification = "Uses non-compiled linq expression")]
        IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> expression);

    	/// <summary>
    	/// Finds all entities matching a lambda expression
    	/// </summary>
    	/// <param name="expression">The expression.</param>
    	/// <param name="selectExpression">Expressions present the properties to be selected</param>
    	/// <returns></returns>
    	[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
            Justification = "Uses non-compiled linq expression")]
        IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity, object>> selectExpression);

        /// <summary>
        /// Finds all entities in the repository
        /// </summary>
        /// <returns></returns>
        IQueryable<TEntity> FindAll();
		
		/// <summary>
        /// Finds all entities in the repository
        /// </summary>
		/// <param name="selectExpression">Expressions present the properties to be selected</param>
		/// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
            Justification = "Uses non-compiled linq expression")]
        IQueryable<TEntity> FindAll(Expression<Func<TEntity, object>> selectExpression);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        IQueryable<TEntity> Find(IEntityCommand<TEntity> command);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        void Execute(IEntityCommand<TEntity> command);

        /// <summary>
        /// 
        /// </summary>
        DataRepositoryCacheOptions CacheOptions { get; }
    }
}
